package raft

func (rf *Raft) ticker() {

	// function : ticker the server start election
	//		1.i'm winner
	//		2.ohter server is winner 3.no winner

	for !rf.killed() {
		// select better than if (when use channel)
		select {
		case <-rf.ElectionTimer.C:
			rf.mu.Lock()
			if rf.state == LEADER {
				rf.mu.Unlock()
				break
			}
			rf.state = CANDIDATOR
			rf.mu.Unlock()
			go rf.startElection()
		}
	}
}

// election is goroutine because when the election timeout ,and there is
// no winner ,we should start a new election
func (rf *Raft) startElection() {

	rf.mu.Lock()
	rf.currentTerm++
	rf.voteFor = rf.me
	rf.state = CANDIDATOR
	rf.ElectionTimer.Reset(randomElctionTimeout())
	rf.mu.Unlock()

	args := RequestVoteArgs{CandidateId: rf.me, Term: rf.currentTerm}

	//send RequestVote to all other server
	voteChan := make(chan bool, len(rf.peers)-1)
	for i := range rf.peers {
		if i == rf.me {
			continue
		}
		// send -> term bigger than myterm -> be follower
		// 		   else: write result to voteChan
		//rf.wgrpc.Add(1)
		go func(i int) {
			//defer rf.wgrpc.Done()
			reply := RequestVoteReply{}
			if ok := rf.sendRequestVote(i, &args, &reply); !ok {
				//fmt.Println("bad net")
				voteChan <- false
				return
			}
			rf.mu.Lock()
			if reply.CurrentTerm > rf.currentTerm {
				rf.currentTerm = reply.CurrentTerm
				rf.voteFor = -1
				rf.state = FOLLOWER
				rf.mu.Unlock()
				return
			}

			voteChan <- reply.VoteGranted

			rf.mu.Unlock()

		}(i)
	}
	//rf.wgrpc.Wait()

	//vote result
	votenum := 1
	votenum_granted := 1
	//fmt.Println("i am ", rf.me, rf.state)
	for i := range voteChan {

		if rf.state != CANDIDATOR {
			break
		}

		if i {
			votenum_granted++
		}

		if votenum_granted > len(rf.peers)/2 {
			rf.mu.Lock()
			rf.state = LEADER
			rf.voteFor = rf.me
			rf.mu.Unlock()
			rf.HeartBeat()
			//fmt.Println(rf.me, "am leader,term :", rf.currentTerm)
			break
		}
		votenum++

		if votenum == len(rf.peers) {
			break
		}
	}
}
